package main

import (
	"math/rand"
)

var (
	seedString string = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"

	letterIdBits int64 = 6 // 通过 6 bit 来推断出一个下标值
	// 此长度的选择应该与seedString的长度自适应

	letterIdMask int64 = 1<<letterIdBits - 1 // 2^6 - 1 =63
	// 将1左移letterIdBits位，如果6位，得到1000000，再减去1得到111111

	letterIdMax int64 = letterIdMask / letterIdBits // 63/6 = 10
)

// GenerateString 生成随机字符串(较快速)
func GenerateString(n int) string {
	b := make([]byte, n)

	/* 通过随机数，构建一个下标值，通过这个下标获取到seedString中对应的符号，然后不断迭代组合，直到长度符合 */
	// src.Int63() 获取一串 63 bit 的随机数字(int64)
	// 期望从随机的一串数字中，按照每 6 bit (letterIdBits)切割并计算出一个int下标值，这串数据则可以切割letterIdMax次
	// 这个随机出来的int64，可以供letterIdMask使用letterIdMax次。
	// 通过&运算得到一个int（这个int小于letterIdMask），以int为下标拿到字符串中的值

	for currentIndex, randInt64, remain := n-1, rand.Int63(), letterIdMax; currentIndex >= 0; {
		if remain == 0 {
			// remain 表示生成的randInt64还可以使用几次（最多为letterIdMax次）
			// 如果次数用尽，则需要生成新的randInt64,并且新的值也可以使用最多letterIdMax次
			randInt64, remain = rand.Int63(), letterIdMax
		}

		if idx := int(randInt64 & letterIdMask); idx < len(seedString) {
			// &运算得到idx，确保 idx <= letterIdMask
			b[currentIndex] = seedString[idx]
			currentIndex--
		}
		// 此时randInt64中有 letterIdBits bit已经使用过，应该丢弃使用过的bits
		randInt64 >>= letterIdBits
		remain--
	}

	return string(b) // 使用string会发生一次内存拷贝
	// return *(*string)(unsafe.Pointer(&b)) // 使用unsafe并发高的时候会导致踩空内存的情况
}
